//////////////////////////////////////////////////////////////////////////////////////////////////////
// 项目名   : Container
// 文件名   : TestList.h
// 作者     : Aiye
// 日期     : 2025/9/4 15:36
// 邮箱     : 2878548868@qq.com
// 摘要     : 介绍list的·用法
//////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef CONTAINER_TESTLIST_H
#define CONTAINER_TESTLIST_H
#include <iostream>
#include <list>
#include <string>

#include "GlobalVariable.h"

/**
 * @brief 测试List的使用
 */
class TestList
{
public:
    /**
     * @brief 测试构造函数
     */
    static void TestConstuctor()
    { // 和vector接口类似
        std::list<int> nList1; // 默认构造函数，构造一个空的链表
        std::list<int> nList2(3); // 构造一个包含3个元素的链表，元素值默认初始化（int为0）
        std::list<int> nList3(3, 3); // 构造一个包含3个元素的链表，每个元素的值都为3
        auto nList4{nList3}; // 拷贝构造函数，深拷贝，不共享内存
        auto nList5{std::move(nList4)}; // 移动构造函数
        std::list<int> nList6{1, 2, 3, 4}; // 初始化列表构造，推荐使用
        decltype(nList6)().swap(nList6); // 使用swap技巧清空并释放list内存
    }

    /**
     * @brief 测试赋值操作
     */
    static void TestAssign()
    { // 和vector接口一致
        std::list<std::string> strList1{"Hello String", "Hello List", "Hello Map"};
        auto strList2 = strList1; // 赋值拷贝，深拷贝，不共享内存
        auto strList3 = std::move(strList2); // 移动赋值拷贝
        std::list<std::string> strList4{};
        strList4.assign(strList1.begin(), strList1.end()); // 使用迭代器范围赋值
        strList4.assign(3, "Hello"); // 赋值3个"Hello"字符串
    }

    /**
     * @brief 测试容量
     */
    static  void TestCapacity()
    {
        std::list<int> nList{1, 2, 3, 4, 5, 6};
        // list没有capacity()概念，因为内存是按需逐个节点分配的
        std::cout << "The list's size:" << nList.size() << std::endl;

        nList.push_back(7);
        nList.push_front(0);
        std::cout << "The list's size:" << nList.size() << std::endl;

        std::cout << "Container is empty: " << nList.empty() << std::endl; // 判断容器是否为空

        // list没有shrink_to_fit()和reserve()成员函数。
        // 内存管理由链表节点自身控制，无需预分配或收缩连续内存。
    }

    /**
     * @brief 测试list的增删
     */
    static void TestCRUD()
    {
        { // 介绍增加操作
            std::list<int> nList{2, 3, 4};

            // 在头部和尾部插入都非常高效 O(1)
            nList.push_back(5);  // 尾部插入
            nList.push_front(1); // 头部插入

            std::list<Person> perList{{"Alice", 18}};
            perList.push_back(Person("Bob", 22));
            perList.push_front(Person("Eve", 21));

            // 就地构造，避免临时对象
            perList.emplace_back("Joker", 21); // 在尾部就地构造
            perList.emplace_front("Mario", 25); // 在头部就地构造

            // 在任意位置插入也非常高效 O(1)，只需修改指针
            auto it = nList.begin();
            std::advance(it, 2); // 将迭代器移动到第三个元素的位置
            nList.insert(it, 99); // 在第三个元素之前插入99
            nList.emplace(it, 88); // 在相同位置就地构造插入88
            nList.insert(it, 3, 20); // 插入3个20
        }

        { // 介绍删除操作
            std::list<int> nList{0, 1, 2, 3, 4, 5, 6, 2};
            nList.pop_back(); // 尾部删除，高效 O(1)
            nList.pop_front(); // 头部删除，高效 O(1)

            auto it = nList.begin();
            std::advance(it, 2);
            nList.erase(it); // 删除指定位置的元素，高效 O(1)

            nList.remove(2); // 删除所有值等于2的元素 O(n)
            nList.remove_if([](int n) { return n % 2 == 0; }); // 删除所有偶数

            nList.clear(); // 清除所有元素
        }

        { // 介绍查操作
            std::list<int> nList{1, 2, 3, 4, 5, 5, 6, 6};

            // list不支持随机访问，没有operator[]和at()成员函数。
            // 访问特定元素需要遍历，时间复杂度为O(n)

            std::cout << "The first element is: " << nList.front() << std::endl; // O(1)
            std::cout << "The last element is: " << nList.back() << std::endl;  // O(1)

            // 查找元素需要使用算法，例如std::find
            auto found_it = std::find(nList.begin(), nList.end(), 4);
            if (found_it != nList.end())
            {
                std::cout << "Found element: " << *found_it << std::endl;
            }
        }

        { // 介绍修改的操作
            std::list<int> nList{1, 2, 3, 4, 5, 6, 7, 8};

            // 修改元素通常需要通过迭代器
            auto it = nList.begin();
            std::advance(it, 2);
            *it = 99; // 修改第三个元素的值

            // 范围for循环修改是安全且常用的方式

            for (int& elem : nList)
            {
                if (elem > 3 && elem < 7)
                {
                    elem *= 2;
                }
            }
        }
    }
};
#endif //CONTAINER_TESTLIST_H